#include <linux/sched/debug.h>
#include <linux/sched.h>
#include <linux/jiffies.h>
#include <linux/timer.h>

struct process_timer
{
    struct timer_list timer;
    struct task_struct *task;
};

static void process_timeout(struct timer_list *t)
{
    struct process_timer *timeout = from_timer(timeout, t, timer);

    wake_up_process(timeout->task);
}

long schedule_timeout(int timeout)
{
    struct process_timer timer;
    unsigned long expire;

    if (timeout < 0)
    {
        schedule();
    }
    else
    {
        timer.task = current;

        expire = jiffies + timeout;

        timer_setup(&timer.timer, process_timeout, 0);
        timer.timer.expires = expire;
        add_timer(&timer.timer);

        schedule();

        del_timer_sync(&timer.timer);

        timeout = expire - jiffies;
    }

    return (timeout < 0)? 0 : timeout;
}

long __sched schedule_timeout_uninterruptible(int timeout)
{
    __set_current_state(TASK_UNINTERRUPTIBLE);

    return schedule_timeout(timeout);
}
